#include <nice2d/background.h>
#include <nice2d/application.h>
#include <nice2d/widgets/desktop.h>
#include <nice2d/widgets/layout.h>

IMPLEMENT_OBJECT(LayoutStyle, ControlStyle)

LayoutStyle::LayoutStyle()
{
    normalBackground = Background::create(sf::Color(128, 128, 62, 128));
    hoverBackground = normalBackground;
    disableBackground = normalBackground;
    pressedBackground = normalBackground;
}

LayoutStyle::~LayoutStyle()
{
}

class LayoutData
{
public:
    Layout *layout;
    std::vector<std::pair<ControlPointer, std::shared_ptr<LayoutInfo>>> widgets;
    float margin = 4.0f;
    float spacing = 3.0f;
    LayoutResizeRule resizeRule = LayoutResizeRule::LayoutResizeRule_ResizeLayout;
    bool dirty = true;

    LayoutData(Layout *thisLayout):
        layout(thisLayout)
    {
        auto desktop = GET_APPLICATION_COMPONENT(Desktop);
        auto style = std::dynamic_pointer_cast<LayoutStyle>(desktop->getControlStyle("Layout"));
        layout->setControlStyle(style);
    }

    void applyStyle()
    {
    }
};

IMPLEMENT_OBJECT(Layout, Control)

Layout::Layout():
    data(new LayoutData(this))
{
}

Layout::~Layout()
{
}

void Layout::setMargin(float margin)
{
    if (data->margin != margin) {
        data->margin = margin;
        data->dirty = true;
    }
}

float Layout::getMargin()const
{
    return data->margin;
}

void Layout::setSpacing(float spacing)
{
    if (data->spacing != spacing) {
        data->spacing = spacing;
        data->dirty = true;
    }
}

float Layout::getSpacing()const
{
    return data->spacing;
}

void Layout::setLayoutResizeRule(LayoutResizeRule rule)
{
    if (data->resizeRule != rule) {
        data->resizeRule = rule;
        data->dirty = true;
    }
}

LayoutResizeRule Layout::getLayoutResizeRule() const
{
    return data->resizeRule;
}

void Layout::addWidget(ControlPointer widget, std::shared_ptr<LayoutInfo> info)
{
    if (widget) {
        data->widgets.push_back(std::make_pair(widget, info));
        addChild(widget);
        widget->setParent(as<Control>());
        data->dirty = true;
    }
}

uint32_t Layout::getWidgetCount() const
{
    return data->widgets.size();
}

std::pair<ControlPointer, std::shared_ptr<LayoutInfo>> Layout::getWidgetByIndex(uint32_t index)
{
    if (index >= getWidgetCount())
        return std::pair<ControlPointer, std::shared_ptr<LayoutInfo>>(nullptr, nullptr);
    return data->widgets.at(index);
}

bool Layout::containsControl(ControlPointer control)
{
    return std::find_if(data->widgets.begin(),
    data->widgets.end(), [&control](const auto & node)->bool {
        return node.first == control;
    }) != data->widgets.end();
}

ControlPointer Layout::getControlBelow(const sf::Vector2i &point)
{
    auto itr = data->widgets.begin();
    while (itr != data->widgets.end()) {
        if ((*itr).first->getControlBelow(point))
            return itr->first;
        itr ++;
    }
    return Control::getControlBelow(point);
}

bool Layout::doesHierarchyContain(ControlPointer other)const
{
    auto itr = data->widgets.begin();
    while (itr != data->widgets.end()) {
        if (itr->first->doesHierarchyContain(other))
            return true;
        itr ++;
    }
    return Control::doesHierarchyContain(other);
}

void Layout::onMouseExit()
{
}

void Layout::onPositionChanged()
{
    adjust();
}

void Layout::onSizeChanged()
{
    adjust();
}

void Layout::onUpdateControl(float deltaTime)
{
    (void)deltaTime;
    if (data->dirty) {
        adjust();
        data->dirty = false;
    }
}
